---
title: Operational runbook
summary: Deployment, health checks, logs, fault conditions, error scenarios, and recovery procedures.
status: draft
owner: Not determined from source
last_reviewed: 2026-09-22
---

# Operational runbook

`ADUserServices` deploys to IIS through the SAIF web-IIS deployment template in two build variants that are materially identical in this repository — same `Release` configuration, same artifact name, same anonymous-authentication setting, and the same `Web.Release.config` transform. Concrete site, virtual-directory, and application-pool details are owned by the external deploy template and are not present in this repository. The service holds no process-wide state, so there is nothing to reset on an application-pool recycle, and it emits no logs of any kind.

## Deployment

| Attribute | Value |
| --- | --- |
| Host | IIS |
| Site / virtual directory | Not determined from source |
| Application pool | Not determined from source (identity sourced from variable group `Architecture.ServiceAccounts.IIS`; see [Authentication and authorization](authentication-authorization.md)) |
| Platform target | Not declared — `BuildPlatformInternal`/`BuildPlatformExternal` are empty values in `pipelines\build-vars.yml` |
| Build configurations | `Release` (both Internal and External variants) |
| Deployment mechanism | `pipelines\release.yml`, extending `/Stages/v2/deploy-stages-web-iis-webservices.yml@templates` |
| Artifacts | `app-internal` — both `ArtifactNameInternal` and `ArtifactNameExternal` are set to this same name ([TD-27](tech-debt.md#high), HIGH) |

## Environments and variants

| Environment | Variant | Address | Environment track | Notes |
| --- | --- | --- | --- | --- |
| Non-production | Internal / External (materially identical) | `<host>/<virtual-directory>/clsADUserServices.asmx` — host and virtual directory not determined from source | `entdev6`, `entdev7`, `enttest6`, `enttest7`, `np14`, `np18`, `np19`, `np20`, `np30`, `np31`, `npuat`, `preprod` (12 tracks) | Each track carries one `allowedips` address in `environmentsettings\settings.yml` |
| Production | Internal / External (materially identical) | `<host>/<virtual-directory>/clsADUserServices.asmx` — host and virtual directory not determined from source | `prod` | Carries four `allowedips` addresses |

The two build variants (Internal/External) are not distinct deployment environments in this repository — they differ only in artifact-naming intent (both currently resolve to `app-internal`, see TD-27) and neither transforms a different configuration value.

## Health verification

| Check | Request | Expected result |
| --- | --- | --- |
| Service metadata reachable | `GET <address>?wsdl` | WSDL document returned |
| Service responds | SOAP request invoking [`HelloWorld`](contracts/clsaduserservices.md#helloworld) | Constant string `"Hello World"` returned; no side effects, no shared state, no directory access |

`HelloWorld` is the lightest available read — it takes no parameters, performs no directory lookup, and cannot fail. No dedicated health endpoint exists in this service; none is invented here.

## Fault conditions

| Condition | What the caller receives | Operator action |
| --- | --- | --- |
| Operation succeeds | Response message (`ADServiceResponse`, `Boolean`, `ArrayList`, or `String` depending on operation) | None |
| Invalid input message | `SoapException` from framework deserialization, or an operation-specific sentinel (e.g. `UserDoesNotExist`) | Return the fault detail to the caller; no server-side action |
| Authorization failure (8 gated operations) | `ADServiceResponse{Response=Failure, Message="Access Denied"}` — never a fault | Verify the caller's source address against the configured `allowedips` track value |
| Allow-list setting missing or environment service unreachable | `SoapException` — unhandled exception propagated out of `CheckAccess` | Verify the `aduserservices.allowedips` setting is provisioned for the deployment track and the environment service is reachable ([TD-12](tech-debt.md#high)) |
| Unknown SOAP action | `SoapException` — method not recognized | Verify the operation name and the `http://tempuri.org/` namespace the caller is using |
| No service at the address | Connection/routing failure at the IIS level — the request never reaches the service, so no SOAP fault is produced | Verify the `.asmx` file deployed and the virtual directory |
| Unhandled exception in an ungated read operation with no `Try`/`Catch` (e.g. `DoesUserHaveResource`, `CheckAccess`) | `SoapException` carrying the .NET exception | Escalate; no logged exception detail exists to reference (see Logs below) |
| Directory failure inside `GetContext`/`GetUserPrincipal`/`GetGroupPrincipal` | Operation-specific sentinel (`UserDoesNotExist`, `GroupDoesNotExist`, `False`, empty list) — never the underlying failure detail | Escalate to Active Directory operations; the service itself provides no diagnostic detail ([BR-34](business-rules.md#br-34-a-directory-lookup-failure-is-reported-as-not-found)) |

## Logs

| Surface | Location | Content | Retention |
| --- | --- | --- | --- |
| None found | Not applicable | Not applicable | Not applicable |

No `log4net` initialization or call, no `Trace.WriteLine`, no `EventLog` write, and no `StreamWriter` exists anywhere in source, despite the `log4net 2.0.5` package reference being present in `packages.config`. This is a negative finding recorded explicitly: there is no logging destination to configure, monitor, or rotate for this service, and no mutating operation (account creation, deletion, password reset, group change) leaves any application-level record of who performed it.

## Environment configuration

| Setting | Key | Purpose |
| --- | --- | --- |
| Allowed IPs | `aduserservices.allowedips` | Comma-separated network-origin allow-list evaluated by `CheckAccess` to gate the eight mutating/password operations |

See [Configuration](configuration.md) for the complete settings catalog, including the embedded domain/container constants that cannot be changed without a rebuild.

## Error scenarios

| Scenario | Symptom | Impact | Recovery |
| --- | --- | --- | --- |
| `aduserservices.allowedips` setting missing for a track | `SoapException` on every gated operation for that track | All 8 mutating operations fail; the 11 read operations are unaffected | Provision the setting in `environmentsettings\settings.yml` for the affected track |
| Environment service unreachable | `SoapException` propagated out of `CheckAccess` | All 8 mutating operations fail; reads continue serving directory data | Verify SAIF environment-service availability |
| Active Directory unavailable | Sentinel (`UserDoesNotExist`/`GroupDoesNotExist`/`False`/empty list) for most operations, or a `SoapException` from the handful of operations with no `Try`/`Catch` (`DoesUserHaveResource`, `CheckAccess`) | Directory-dependent operations degrade; the failure detail is not surfaced to the caller | Verify the configured directory domains (`external.saif.com`, `corp.saif.com`) and connectivity |
| Log directory unavailable | Not applicable — no logging surface exists | Not applicable | Not applicable |
| Application pool recycled under load | No impact — no process-wide cache, counter, or shared state exists in this service (see [Architecture](architecture.md)) | None | None required |
| Stale cached data served | Not applicable — no cache exists | Not applicable | Not applicable |
| Hard-coded default password in effect for accounts created with an empty `inPassword` | Newly-created accounts share a single known credential | Any holder of that credential can authenticate as any account created without an explicit password | Always supply an explicit `inPassword`; remediate per [Tech debt](tech-debt.md) (SEC-05, CRITICAL) |

## Monitoring and alerting

| Alert | Trigger | Recipient | Severity |
| --- | --- | --- | --- |
| None configured | Not applicable | Not applicable | Not applicable |

No telemetry, fault-rate alert, or availability probe is configured anywhere in this repository. This is stated plainly rather than describing a hypothetical alert.

## Related documentation
- [Service index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Activation and hosting](activation-hosting.md)
- [Operations](operations.md)
- [Operations and processes](operations-processes.md)
- [Authentication and authorization](authentication-authorization.md)
- [Business rules](business-rules.md)
- [Configuration](configuration.md)
- [Dependencies](dependencies.md)
- [Faults and error pipeline](faults.md)
- [Tech debt](tech-debt.md)

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Sources
- `pipelines\release.yml`
- `pipelines\build-vars.yml`
- `environmentsettings\settings.yml`
- `src\ADUserServices\clsADUserServices.asmx.vb`
- `.saifdocgen\state\runs\20260922-101326-aduserservices\analysis\aduserservices-analysis.md`
